/*
 * File Name: ActionFactory.java
 */

package co.edu.uniandes.intercon.client.action;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Map.Entry;

import co.edu.uniandes.intercon.server.process.AbstractBaseProcess;
import co.edu.uniandes.intercon.server.util.P2PLogger;

/**
 * Factory used to retrieve actions
 * 
 * @author Fabian Gutierrez [fagossa@gmail.com]
 */
public class ActionFactory {

	private static Map<String, Object> operationsCache = new HashMap<String, Object>();

	private static Properties actions = new Properties();

	static {
		try {
			// load the action configuration
			actions.load(ActionFactory.class
					.getResourceAsStream("actions.properties"));
		} catch (IOException ex) {
			throw new IllegalStateException(
					"the actions configuration file could't be found!");
		}
	}

	/**
	 * Gets the gui action according to the key specified
	 * 
	 * @param operationName
	 *            Name of the gui operation used to retrieve the cached action
	 * @return OperacionMoneyGram Action instance used to handle the operation
	 *         specified
	 */
	public static AbstractBaseGUIAction getGUIAction(String operationName) {
		return (AbstractBaseGUIAction) getAction("gui." + operationName);
	}

	/**
	 * 
	 * @return
	 */
	public static List<AbstractBaseProcess> getAllVisibleProccesses() {
		List<AbstractBaseProcess> processes = new ArrayList<AbstractBaseProcess>();
		Set<Entry<Object, Object>> elements = actions.entrySet();
		Iterator items = elements.iterator();
		while (items.hasNext()) {
			Entry item = (Entry) items.next();
			String name = item.getKey().toString();
			if (name.startsWith("pro")) {
				AbstractBaseProcess element = (AbstractBaseProcess) getAction(name);
				if (element.isVisible()) {
					processes.add((AbstractBaseProcess) element);
				}
			}
		}
		return processes;
	}

	/**
	 * 
	 * @return
	 */
	public static List<AbstractBaseProcess> getAllProccesses() {
		List<AbstractBaseProcess> processes = new ArrayList<AbstractBaseProcess>();
		Set<Entry<Object, Object>> elements = actions.entrySet();
		Iterator items = elements.iterator();
		while (items.hasNext()) {
			Entry item = (Entry) items.next();
			String name = item.getKey().toString();
			if (name.startsWith("pro")) {
				AbstractBaseProcess element = (AbstractBaseProcess) getAction(name);
				processes.add((AbstractBaseProcess) element);
			}
		}
		return processes;
	}

	/*
	 * Retrieves a cache action
	 */
	private static Object getAction(String key) {
		Object action = operationsCache.get(key);
		if (action == null) {
			try {
				final String operationClassName = (String) actions.get(key);

				ClassLoader loader = Thread.currentThread()
						.getContextClassLoader();
				Class clazz = loader.loadClass(operationClassName);
				action = clazz.newInstance();

				operationsCache.put(key, action);
			} catch (Exception ex) {
				P2PLogger.logError("Error finding the action specified", ex);
				throw new IllegalStateException(
						"Error finding the action specified");
			}
		}

		return action;
	}

	/**
	 * Retrieves a process by its class name
	 * 
	 * @param implClass
	 *            Name of the class to be searched
	 * @return instance of <code>AbstractBaseProcess</code> or empty string
	 */
	public static AbstractBaseProcess findProccesByClassName(String implClass) {
		AbstractBaseProcess result = null;
		List<AbstractBaseProcess> processes = getAllVisibleProccesses();
		if (processes != null) {
			for (AbstractBaseProcess currProcess : processes) {
				if (currProcess.getClass().getName().equals(implClass)) {
					result = currProcess;
					break;
				}
			}
		}
		return result;
	}
}
